<?php

class PicoIOCResolver {
  
  var $m_setupDir;

  function PicoIOCResolver ($setupDir) {
    $this->m_setupDir = $setupDir;
  }
  
  function & resolv ($name) {
    $shortPath = $this->m_setupDir.$name.'.inc';
    $longPath = $shortPath.'.php';
    if (file_exists($longPath)) {
      return $longPath;
    } else {
      if (file_exists($shortPath)) {
        return $shortPath;
      } else {
        return null;
      }
    }
  }
  
}

class PicoIOCFactory {

  var $m_recentIsSingleton;
  var $m_ioc;

  function PicoIOCFactory (&$ioc) {
    $this->m_ioc =& $ioc;
  }

  function bind_obj(&$instance, $binds) {
    foreach ($binds as $attrName => $objName) {
      $setter = "set_$attrName";
      if (method_exists($instance, $setter)) {
        $instance->$setter($this->m_ioc->get($objName));
      }
    }
  }

  function bind_const(&$instance, $binds) {
    foreach ($binds as $attrName => $value) {
      $setter = "set_$attrName";
      if (method_exists($instance, $setter)) {
        $instance->$setter($value);
      }
    }
  }
  
  function & _load_script($path) {
    require $path;
    return $instance;
  }

  function singleton() {
    $this->m_recentIsSingleton = true;
  }

  function is_singleton() {
    return $this->m_recentIsSingleton;
  }
  
  function & instantiate($path) {
    $this->m_recentIsSingleton = false;
    $instance =& $this->_load_script($path);
    if (method_exists($instance, 'post_configure')) {
      $instance->post_configure();
    }
    return $instance;
  }

}

class PicoIOC {

  var $m_shortcuts;
  var $m_resolvers;
  var $m_singletons;
  var $m_factory;
  

  function PicoIOC ($shortcuts, $resolvers, $factory = 'PicoIOCFactory') {
    $this->m_shortcuts =& $shortcuts;
    $this->m_resolvers =& $resolvers;
    $this->m_factory =& new $factory($this);
    $this->m_singletons = array();
  }

  function & get($name) {
    if (isset($this->m_shortcuts[$name])) {
      return $this->_get_shortcut($name);
    }
    if (isset($this->m_singleton[$name])) {
      $instance =& $this->m_singleton[$name];
    } else {
      $path = $this->get_path_for_name($name);
      $instance =& $this->m_factory->instantiate($path);
      if ($this->m_factory->is_singleton()) {
        $this->m_ioc->m_singleton[$name] =& $instance;
      }
    }
    return $instance;
  }

  function & _get_shortcut($name) {
    $shortcut =& $this->m_shortcuts[$name];
    $singleton = $shortcut[0];
    if ($singleton && isset($this->m_singleton[$name])) {
      return $this->m_singleton[$name];
    }
    $className = $shortcut[1];
    $instance =& new $className();
    if (isset($shortcut[2])) {
      $this->m_factory->bind_const($instance, $shortcut[2]);
    }
    if ($singleton) {
      $this->m_singleton[$name] =& $instance;
    }
    return $instance;
  }

  function get_path_for_name($name) {
    for($i = 0, $len = count($this->m_resolvers); $i < $len; $i++) {
      $resolver =& $this->m_resolvers[$i];
      $path = $resolver->resolv($name);
      if ($path !== null) {
        return $path;
      }
    }
  }

}

?>
